home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / apps / 223 / emacssrc / line.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-02-17  |  14.5 KB  |  629 lines

  1. /*
  2.  * The functions in this file
  3.  * are a general set of line management
  4.  * utilities. They are the only routines that
  5.  * touch the text. They also touch the buffer
  6.  * and window structures, to make sure that the
  7.  * necessary updating gets done. There are routines
  8.  * in this file that handle the kill buffer too.
  9.  * It isn't here for any good reason.
  10.  *
  11.  * Note that this code only updates the dot and
  12.  * mark values in the window list. Since all the code
  13.  * acts on the current window, the buffer that we
  14.  * are editing must be being displayed, which means
  15.  * that "b_nwnd" is non zero, which means that the
  16.  * dot and mark values in the buffer headers are
  17.  * nonsense.
  18.  */
  19. #include    <stdio.h>
  20. #include    "ed.h"
  21.  
  22. char    *kbufp    = NULL;            /* Kill buffer data        */
  23. int    kused    = 0;            /* # of bytes used in KB    */
  24. int    ksize    = 0;            /* # of bytes allocated in KB    */
  25.  
  26. /*
  27.  * This routine allocates a block
  28.  * of memory large enough to hold a LINE
  29.  * containing "used" characters. The block is
  30.  * always rounded up a bit. Return a pointer
  31.  * to the new block, or NULL if there isn't
  32.  * any memory left. Print a message in the
  33.  * message line if no space.
  34.  */
  35. LINE    *
  36. lnalloc(used)
  37.     register int    used;
  38.     {
  39.     register LINE    *lp;
  40.     register int    size, block;
  41.  
  42.     size = used + NBLOCK;
  43.     if (size > MAXUS)
  44.         size = MAXUS;
  45.     if (size < used) 
  46.         {
  47.         mlwrite("Line too long");
  48.         return (NULL);
  49.         }
  50.     block = sizeof(LINE) + size;
  51.     lp = (LINE *) malloc(block);
  52.     if (lp == NULL) 
  53.         {
  54.         dtmpbufs();            /* mb: clear temp bufs    */
  55.         lp = (LINE *) malloc(block);    /*  and try again    */
  56.         if (lp == NULL) 
  57.             {
  58.             mlwrite("Not enough memory");
  59.             return (NULL);
  60.             }
  61.         }
  62.     lp->l_size = size;
  63.     lp->l_used = used;
  64.     return (lp);
  65.     }
  66.  
  67. /*
  68.  * Delete line "lp". Fix all of the
  69.  * links that might point at it (they are
  70.  * moved to offset 0 of the next line.
  71.  * Unlink the line from whatever buffer it
  72.  * might be in. Release the memory. The
  73.  * buffers are updated too; the magic conditions
  74.  * described in the above comments don't hold
  75.  * here.
  76.  */
  77. lfree(lp)
  78. register LINE    *lp;
  79.     {
  80.     register BUFFER    *bp;
  81.     register WINDOW    *wp;
  82.  
  83.     wp = wheadp;
  84.     while (wp != NULL) 
  85.         {
  86.         if (wp->w_linep == lp)
  87.             wp->w_linep = lp->l_fp;
  88.         if (wp->w_dotp  == lp) 
  89.             {
  90.             wp->w_dotp  = lp->l_fp;
  91.             wp->w_doto  = 0;
  92.             }
  93.         if (wp->w_markp == lp) 
  94.             {
  95.             wp->w_markp = lp->l_fp;
  96.             wp->w_marko = 0;
  97.             }
  98.         wp = wp->w_wndp;
  99.         }
  100.     bp = bheadp;
  101.     while (bp != NULL) 
  102.         {
  103.         if (bp->b_nwnd == 0) 
  104.             {
  105.             if (bp->b_dotp  == lp) 
  106.                 {
  107.                 bp->b_dotp = lp->l_fp;
  108.                 bp->b_doto = 0;
  109.                 }
  110.             if (bp->b_markp == lp) 
  111.                 {
  112.                 bp->b_markp = lp->l_fp;
  113.                 bp->b_marko = 0;
  114.                 }
  115.             }
  116.         bp = bp->b_bufp;
  117.         }
  118.     lp->l_bp->l_fp = lp->l_fp;
  119.     lp->l_fp->l_bp = lp->l_bp;
  120.     free((char *) lp);
  121.     }
  122.  
  123. /*
  124.  * This routine gets called when
  125.  * a character is changed in place in the
  126.  * current buffer. It updates all of the required
  127.  * flags in the buffer and window system. The flag
  128.  * used is passed as an argument; if the buffer is being
  129.  * displayed in more than 1 window we change EDIT to
  130.  * HARD. Set MODE if the mode line needs to be
  131.  * updated (the "*" has to be set).
  132.  */
  133. lchange(flag)
  134. register int    flag;
  135.  
  136.     {
  137.     register WINDOW    *wp;
  138.  
  139.     if (curbp->b_nwnd != 1)            /* Ensure hard.        */
  140.         flag = WFHARD;
  141.     if ((curbp->b_flag&BFCHG) == 0)     /* First change, so     */
  142.         {
  143.         flag |= WFMODE;            /* update mode lines.    */
  144.         curbp->b_flag |= BFCHG;
  145.         }
  146.     wp = wheadp;
  147.     while (wp != NULL) 
  148.         {
  149.         if (wp->w_bufp == curbp)
  150.             wp->w_flag |= flag;
  151.         wp = wp->w_wndp;
  152.         }
  153.     }
  154.  
  155. /* Insert "n" copies of the character "c"
  156.  * at the current location of dot. In the easy case
  157.  * all that happens is the text is stored in the line.
  158.  * In the hard case, the line has to be reallocated.
  159.  * When the window list is updated, take special
  160.  * care; I screwed it up once. You always update dot
  161.  * in the current window. You update mark, and a
  162.  * dot in another window, if it is greater than
  163.  * the place where you did the insert. Return TRUE
  164.  * if all is well, and FALSE on errors.
  165.  * mb: added overstrike capability.
  166.  */
  167. linsert(n, c, overstrike)
  168.     {
  169.     register char    *cp1;
  170.     register char    *cp2;
  171.     register LINE    *lp1;
  172.     register LINE    *lp2;
  173.     register int    i;
  174.     LINE    *lp3;
  175.     char    *cp3;
  176.     WINDOW    *wp;
  177.     int    doto, insert, newsize;
  178.  
  179.         insert = !overstrike;
  180.         lchange(WFEDIT);
  181.     lp1 = curwp->w_dotp;            /* Current line        */
  182.     if (lp1 == curbp->b_linep)         /* At the end: special    */
  183.         {
  184.         if ((lp2=lnalloc(n)) == NULL)    /* Allocate new line    */
  185.             return (FALSE);
  186.         lp3 = lp1->l_bp;        /* Previous line    */
  187.         lp3->l_fp = lp2;        /* Link in        */
  188.         lp2->l_fp = lp1;
  189.         lp1->l_bp = lp2;
  190.         lp2->l_bp = lp3;
  191.         for (i=0; i<n; i++)
  192.             lp2->l_text[i] = c;
  193.         curwp->w_dotp = lp2;
  194.         curwp->w_doto = n;
  195.         return (TRUE);
  196.         }
  197.     doto = curwp->w_doto;
  198.     if (insert)
  199.         newsize = llength(lp1) + n;
  200.     else
  201.         newsize = doto + n;
  202.     if (newsize > lsize(lp1))         /* hard: need new space */
  203.         {
  204.         if ((lp2=lnalloc(newsize))==NULL)
  205.             return (FALSE);
  206.         cp1 = &(lp1->l_text[0]);        /* old text  */
  207.         cp2 = &(lp2->l_text[0]);        /* new space */
  208.         cp3 = &(lp1->l_text[doto]);        /* cursor */
  209.         while (cp1 < cp3)
  210.             *cp2++ = *cp1++;    /* copy text left of dot */
  211.         if (insert)             /* leave gap, copy rest  */
  212.             {
  213.             cp2 += n;
  214.             cp3 = &(lp1->l_text[llength(lp1)]);
  215.             while (cp1 < cp3)
  216.                 *cp2++ = *cp1++;
  217.             }
  218.         lp1->l_bp->l_fp = lp2;        /* link in new line    */
  219.         lp2->l_fp = lp1->l_fp;
  220.         lp1->l_fp->l_bp = lp2;
  221.         lp2->l_bp = lp1->l_bp;
  222.         free((char *) lp1);
  223.         }
  224.     else                     /* Easy: in place    */
  225.         {
  226.         lp2 = lp1;            /* Pretend new line    */
  227.         if (overstrike) 
  228.             {
  229.             if (llength(lp2) < doto+n)
  230.                 lp2->l_used = doto+n;
  231.             }
  232.         else 
  233.             {
  234.             lp2->l_used += n;
  235.             cp2 = &(lp2->l_text[llength(lp2)]);
  236.             cp1 = cp2-n;
  237.             cp3 = &(lp2->l_text[doto]);
  238.             while (cp1 > cp3)
  239.                 *--cp2 = *--cp1;
  240.             }
  241.         }
  242.     cp2 = &(lp2->l_text[doto]);    /* Add the new characters */
  243.     for (i=0; i<n; i++)
  244.         *cp2++ = c;
  245.     wp = wheadp;            /* Update windows      */
  246.     while (wp != NULL) 
  247.         {
  248.         if (wp->w_linep == lp1)
  249.             wp->w_linep = lp2;
  250.         if (wp->w_dotp == lp1) 
  251.             {
  252.             wp->w_dotp = lp2;
  253.             if (wp==curwp || (insert && (wp->w_doto > doto)))
  254.                 wp->w_doto += n;
  255.             }
  256.         if (wp->w_markp == lp1) 
  257.             {
  258.             wp->w_markp = lp2;
  259.             if (insert && (wp->w_marko > doto))
  260.                 wp->w_marko += n;
  261.             }
  262.         wp = wp->w_wndp;
  263.         }
  264.     return (TRUE);
  265.     }
  266.  
  267. /*
  268.  * Insert a newline into the buffer
  269.  * at the current location of dot in the current
  270.  * window. The funny ass-backwards way it does things
  271.  * is not a botch; it just makes the last line in
  272.  * the file not a special case. Return TRUE if everything
  273.  * works out and FALSE on error (memory allocation
  274.  * failure). The update of dot and mark is a bit
  275.  * easier then in the above case, because the split
  276.  * forces more updating.
  277.  */
  278. lnewline()
  279.     {
  280.     register char    *cp1;
  281.     register char    *cp2;
  282.     register LINE    *lp1;
  283.     register LINE    *lp2;
  284.     register int    doto;
  285.     register WINDOW    *wp;
  286.  
  287.     lchange(WFHARD);
  288.     lp1  = curwp->w_dotp;            /* Get the address and    */
  289.     doto = curwp->w_doto;            /* offset of "."    */
  290.     if ((lp2=lnalloc(doto)) == NULL)    /* New first half line    */
  291.         return (FALSE);
  292.     cp1 = &lp1->l_text[0];            /* Shuffle text around    */
  293.     cp2 = &lp2->l_text[0];
  294.     while (cp1 < &lp1->l_text[doto])
  295.         *cp2++ = *cp1++;
  296.     cp2 = &lp1->l_text[0];
  297.     while (cp1 < &(lp1->l_text[llength(lp1)]))
  298.         *cp2++ = *cp1++;
  299.     lp1->l_used -= doto;
  300.     lp2->l_bp = lp1->l_bp;
  301.     lp1->l_bp = lp2;
  302.     lp2->l_bp->l_fp = lp2;
  303.     lp2->l_fp = lp1;
  304.     wp = wheadp;                /* Windows        */
  305.     while (wp != NULL) 
  306.         {
  307.         if (wp->w_linep == lp1)
  308.             wp->w_linep = lp2;
  309.         if (wp->w_dotp == lp1) 
  310.             {
  311.             if (wp->w_doto < doto)
  312.                 wp->w_dotp = lp2;
  313.             else
  314.                 wp->w_doto -= doto;
  315.             }
  316.         if (wp->w_markp == lp1) 
  317.             {
  318.             if (wp->w_marko < doto)
  319.                 wp->w_markp = lp2;
  320.             else
  321.                 wp->w_marko -= doto;
  322.             }
  323.         wp = wp->w_wndp;
  324.         }    
  325.     return (TRUE);
  326.     }
  327.  
  328. /*
  329.  * This function deletes "n" bytes,
  330.  * starting at dot. It understands how do deal
  331.  * with end of lines, etc. It returns TRUE if all
  332.  * of the characters were deleted, and FALSE if
  333.  * they were not (because dot ran into the end of
  334.  * the buffer. The "kflag" is TRUE if the text
  335.  * should be put in the kill buffer.
  336.  */
  337. ldelete(n, kflag)
  338.     {
  339.     register char    *cp1;
  340.     register char    *cp2;
  341.     register LINE    *dotp;
  342.     register int    doto;
  343.     register int    chunk;
  344.     register WINDOW    *wp;
  345.  
  346.     if (kflag != FALSE)             /* mb: added */
  347.         {
  348.         if ((lastflag&CFKILL) == 0)
  349.             kdelete();
  350.         thisflag |= CFKILL;
  351.         if (enlrg_kbuf(n) != TRUE)
  352.             return (FALSE);
  353.         }
  354.     while (n > 0) 
  355.         {
  356.         dotp = curwp->w_dotp;
  357.         doto = curwp->w_doto;
  358.         if (dotp == curbp->b_linep)    /* Hit end of buffer.    */
  359.             return (FALSE);
  360.         chunk = llength(dotp)-doto;    /* Size of chunk.    */
  361.         if (chunk > n)
  362.             chunk = n;
  363.         if (chunk == 0)         /* End of line, merge.    */
  364.             {
  365.             lchange(WFHARD);
  366.             if (ldelnewline() == FALSE
  367.             || (kflag!=FALSE && kinsert('\n')==FALSE))
  368.                 return (FALSE);
  369.             --n;
  370.             continue;
  371.             }
  372.         lchange(WFEDIT);
  373.         cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
  374.         cp2 = cp1 + chunk;
  375.         if (kflag != FALSE)         /* Kill?        */
  376.             {
  377.             while (cp1 < cp2) 
  378.                 {
  379.                 if (kinsert(*cp1) == FALSE)
  380.                     return (FALSE);
  381.                 ++cp1;
  382.                 }
  383.             cp1 = &dotp->l_text[doto];
  384.             }
  385.         while (cp2 < &dotp->l_text[llength(dotp)])
  386.             *cp1++ = *cp2++;
  387.         dotp->l_used -= chunk;
  388.         wp = wheadp;            /* Fix windows        */
  389.         while (wp != NULL) 
  390.             {
  391.             if (wp->w_dotp==dotp && wp->w_doto>=doto) 
  392.                 {
  393.                 wp->w_doto -= chunk;
  394.                 if (wp->w_doto < doto)
  395.                     wp->w_doto = doto;
  396.                 }    
  397.             if (wp->w_markp==dotp && wp->w_marko>=doto) 
  398.                 {
  399.                 wp->w_marko -= chunk;
  400.                 if (wp->w_marko < doto)
  401.                     wp->w_marko = doto;
  402.                 }
  403.             wp = wp->w_wndp;
  404.             }
  405.         n -= chunk;
  406.         }
  407.     curwp->w_force = 0;    /* mb: if reframe, to middle */
  408.     return (TRUE);
  409.     }
  410.  
  411. /*
  412.  * Delete a newline. Join the current line
  413.  * with the next line. If the next line is the magic
  414.  * header line always return TRUE; merging the last line
  415.  * with the header line can be thought of as always being a
  416.  * successful operation, even if nothing is done, and this makes
  417.  * the kill buffer work "right". Easy cases can be done by
  418.  * shuffling data around. Hard cases require that lines be moved
  419.  * about in memory. Return FALSE on error and TRUE if all
  420.  * looks ok. Called by "ldelete" only.
  421.  */
  422. ldelnewline()
  423.     {
  424.     register char    *cp1;
  425.     register char    *cp2;
  426.     register LINE    *lp1;
  427.     register LINE    *lp2;
  428.     register LINE    *lp3;
  429.     register WINDOW    *wp;
  430.  
  431.     lp1 = curwp->w_dotp;
  432.     lp2 = lp1->l_fp;
  433.     if (lp2 == curbp->b_linep)         /* At the buffer end.    */
  434.         {
  435.         if (llength(lp1) == 0)        /* Blank line.        */
  436.             lfree(lp1);
  437.         return (TRUE);
  438.         }
  439.     if (llength(lp2) <= lsize(lp1)-llength(lp1)) 
  440.         {
  441.         cp1 = &lp1->l_text[llength(lp1)];
  442.         cp2 = &lp2->l_text[0];
  443.         while (cp2 < &lp2->l_text[llength(lp2)])
  444.             *cp1++ = *cp2++;
  445.         wp = wheadp;
  446.         while (wp != NULL) 
  447.             {
  448.             if (wp->w_linep == lp2)
  449.                 wp->w_linep = lp1;
  450.             if (wp->w_dotp == lp2) 
  451.                 {
  452.                 wp->w_dotp  = lp1;
  453.                 wp->w_doto += llength(lp1);
  454.                 }
  455.             if (wp->w_markp == lp2) 
  456.                 {
  457.                 wp->w_markp  = lp1;
  458.                 wp->w_marko += llength(lp1);
  459.                 }
  460.             wp = wp->w_wndp;
  461.             }        
  462.         lp1->l_used += llength(lp2);
  463.         lp1->l_fp = lp2->l_fp;
  464.         lp2->l_fp->l_bp = lp1;
  465.         free((char *) lp2);
  466.         return (TRUE);
  467.         }
  468.     if ((lp3=lnalloc(llength(lp1)+llength(lp2))) == NULL)
  469.         return (FALSE);
  470.     cp1 = &lp1->l_text[0];
  471.     cp2 = &lp3->l_text[0];
  472.     while (cp1 < &lp1->l_text[llength(lp1)])
  473.         *cp2++ = *cp1++;
  474.     cp1 = &lp2->l_text[0];
  475.     while (cp1 < &lp2->l_text[llength(lp2)])
  476.         *cp2++ = *cp1++;
  477.     lp1->l_bp->l_fp = lp3;
  478.     lp3->l_fp = lp2->l_fp;
  479.     lp2->l_fp->l_bp = lp3;
  480.     lp3->l_bp = lp1->l_bp;
  481.     wp = wheadp;
  482.     while (wp != NULL) 
  483.         {
  484.         if (wp->w_linep==lp1 || wp->w_linep==lp2)
  485.             wp->w_linep = lp3;
  486.         if (wp->w_dotp == lp1)
  487.             wp->w_dotp  = lp3;
  488.         else if (wp->w_dotp == lp2) 
  489.             {
  490.             wp->w_dotp  = lp3;
  491.             wp->w_doto += llength(lp1);
  492.             }
  493.         if (wp->w_markp == lp1)
  494.             wp->w_markp  = lp3;
  495.         else if (wp->w_markp == lp2) 
  496.             {
  497.             wp->w_markp  = lp3;
  498.             wp->w_marko += llength(lp1);
  499.             }
  500.         wp = wp->w_wndp;
  501.         }
  502.     free((char *) lp1);
  503.     free((char *) lp2);
  504.     return (TRUE);
  505.     }
  506.  
  507. /*
  508.  * Delete all of the text
  509.  * saved in the kill buffer. Called by commands
  510.  * when a new kill context is being created. The kill
  511.  * buffer array is released, just in case the buffer has
  512.  * grown to immense size. No errors.
  513.  */
  514. kdelete()
  515.     {
  516.     if (kbufp != NULL) 
  517.         {
  518.         free((char *) kbufp);
  519.         kbufp = NULL;
  520.         kused = 0;
  521.         ksize = 0;
  522.         }
  523.     }
  524.  
  525. /* mb: simplified, calls enlrg_kbuf().
  526.  * Insert a character to the kill buffer,
  527.  * enlarging the buffer if there isn't any room. Always
  528.  * grow the buffer in chunks, on the assumption that if you
  529.  * put something in the kill buffer you are going to put
  530.  * more stuff there too later. Return TRUE if all is
  531.  * well, and FALSE on errors.
  532.  */
  533. kinsert(c)
  534.     int c;
  535.     {
  536.     if (kused >= ksize) 
  537.         {
  538.         if (enlrg_kbuf(1) != TRUE)
  539.             return (FALSE);
  540.         }
  541.     kbufp[kused++] = (char) c;
  542.     return (TRUE);
  543.     }
  544.  
  545. /*
  546.  * mb: added. To enable preparation of a big kbuf.
  547.  */
  548. enlrg_kbuf(size)
  549.     register int size;
  550.     {
  551.     register char *cp1;
  552.     register char *cp2;
  553.     register int  i;
  554.     char          *newkbuf;
  555.  
  556.     if (size < 0)                /* overflow        */
  557.         return (FALSE);
  558.     size += kused;
  559.     if (size < 0)                /* overflow        */
  560.         return (FALSE);
  561.     if (size < ksize)            /* don't overdo it    */
  562.         return (TRUE); 
  563.     size += KBLOCK;
  564.     if (size < 0)                /* overflow        */
  565.         return (FALSE);
  566.     newkbuf = (char *) malloc(size);
  567.     if (newkbuf == NULL) 
  568.         {
  569.         dtmpbufs();            /* mb: clear temp bufs    */
  570.         newkbuf = (char *) malloc(size);/*  and try again    */
  571.         if (newkbuf == NULL)
  572.             return (FALSE);
  573.         }
  574.     if (kbufp != NULL) 
  575.         {
  576.         cp1 = kbufp;
  577.         cp2 = newkbuf;
  578.         for(i=0; i<kused; i++)
  579.             *cp2++ = *cp1++;
  580.         free(kbufp);
  581.         }
  582.     kbufp = newkbuf;
  583.     ksize = size;
  584.     return (TRUE);
  585.     }
  586.  
  587. /*
  588.  * This function gets characters from
  589.  * the kill buffer. If the character index "n" is
  590.  * off the end, it returns "-1". This lets the caller
  591.  * just scan along until it gets a "-1" back.
  592.  */
  593. kremove(n)
  594.     {
  595.     if (n >= kused)
  596.         return (-1);
  597.     else
  598.         return (kbufp[n] & 0xFF);
  599.     }
  600.  
  601.  
  602. /*
  603.  * mb: added.
  604.  * Twiddle this and former line.
  605.  * Real easy: switch pointers.
  606.  * Bound to C-X C-T.
  607.  */
  608. ltwiddle(f,n) 
  609.     {
  610.     register LINE *lp;
  611.     register LINE *tp;
  612.  
  613.     lp = curwp->w_dotp;
  614.     if (lp == curbp->b_linep)
  615.         return (FALSE);
  616.     tp = lp;
  617.     lp = lback(lp);
  618.     if (lp == curbp->b_linep)
  619.         return (FALSE);
  620.     lforw(lback(lp)) = tp;
  621.     lback(tp) = lback(lp);
  622.     lback(lp) = tp;
  623.     lforw(lp) = lforw(tp);
  624.     lback(lforw(tp)) = lp;
  625.     lforw(tp) = lp;
  626.     lchange(WFHARD);
  627.     return (TRUE);
  628.     }
  629.